
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;
using Swaf.Container;

using System.Xml;
using System.Xml.XPath;

using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Core;

namespace BackupRestoreDeploy
{

	public class BackUpBizRules : Syrinx.BaseBizRules
	{
		static string[] s_systemDirs = { "App_ThemeMasters", "App_Themes", "BaseCode", "bin", "configFiles", "fckeditor", "GenBin", "js", "NibotiStyles", "obj", "Properties", "styles", "SyntaxHighlighter" };
		static string[] s_pageOnlyFileFilters = { "*.aspx", "*.cs", "*.inc", "*.htm", "*.html", "*.inc", "*.txt", "*.ascx"};
		public void executeCompanyBackup(IApplication app, IRuleContext context, IBizObj dInfo, ZipOutputStream zOut)
		{
			try
			{
				app.sessionData["InBackup"] = true;
				Debug.Assert(zOut != null && dInfo != null);
				string root = app.resMgr.resolve("$ConfigParam1$");
				string comment = dInfo.get("comments").ToString();
				string shortName = "";

				//Write the actual deployment info bizobj as a file, so that it can be recreated
				//just from the zip file.
				zOut.PutNextEntry(new ZipEntry(BackupManagementBizRules.DeploymentInfoFileName));
				TextWriter t = new StreamWriter(zOut);
				t.Write(dInfo.Xml);
				t.Flush();
				context.put("zipWriter", t);

				if (root.StartsWith("file://"))
					root = root.Substring(7);

				foreach (IBizObj company in dInfo.get("backupCompanies") as IBizObjList)
				{
					shortName = company.get("shortName").ToString();
					string templatePath = Cmn.pathCombine(app.resMgr.getMacro("BackupRestoreFileStore"), shortName);
					templatePath = Cmn.pathCombine(root, templatePath);

					zOut.SetComment(comment);

					if (BackupHelper.shouldPerform(dInfo, "includeSitePages"))
					{
						List<string> skipDirs = new List<string>();
						skipDirs.AddRange(s_systemDirs);
						IBizObjList childCompanies = app.ruleMgr.execute(context, "getChildCompanies", company.get("id"), false).CallResults as IBizObjList;
						foreach (IBizObj child in childCompanies)
							skipDirs.Add((string)child.get("shortName"));
						string startDir = company.get("parentId") == null ? root : Cmn.pathCombine(root, shortName);
						processDirsAndFiles(zOut, startDir, "", s_pageOnlyFileFilters, shortName, true, skipDirs);
					}
				}
			}
			catch (Exception e)
			{
				throw new BackupRestoreDeployException("error executing createDeployment.", e);
			}
		}

		//public void executeSiteDeploymentBackup(IApplication app, IRuleContext context, IBizObj dInfo, ZipOutputStream zOut)
		//{
		//    Debug.Assert(zOut != null && dInfo != null);
		//    string root = app.resMgr.resolve("$ConfigParam1$");
		//    XmlDocument doc = new XmlDocument();
		//    string shortName = null;
		//    IBizObjList list = dInfo.get("features") as IBizObjList;
		//    foreach (IBizObj obj in list)
		//    {
		//        string xmlFilename = obj.get("xmlFile").ToString();
		//        string xml = Cmn.pathCombine(root, string.Format("configFiles{0}Features{0}{1}", Path.DirectorySeparatorChar, xmlFilename));
		//        if (File.Exists(xml))
		//        {
		//            doc.Load(xml);
		//            //processing bin
		//            XmlNodeList binDependencies = doc.DocumentElement.SelectNodes("Dependencies/Dependency[@type='binary']");
		//            foreach (XmlElement dep in binDependencies)
		//            {
		//                string fileName = Cmn.pathCombine(root.Substring(0, root.Length - 3), dep.InnerText);
		//                if (File.Exists(fileName))
		//                {
		//                    string entryName = string.Format("bin/{0}", dep.InnerText);
		//                    zipOutHelper(zOut, fileName, entryName, shortName);
		//                }
		//            }
		//            //processing dar 
		//            XmlNodeList darDependencies = doc.DocumentElement.SelectNodes("Catalogs/Entry");
		//            foreach (XmlElement dep in darDependencies)
		//            {
		//                string entryName = string.Format(@"configFiles/Catalogs/DataRequestDefinitions/{0}/", dep.InnerText);
		//                string dirName = Cmn.pathCombine(root, entryName);
		//                if (Directory.Exists(dirName))
		//                {
		//                    string[] files = Directory.GetFiles(dirName, "*.xml");
		//                    for (int j = 0; j < files.Length; j++)
		//                        zipOutHelper(zOut, files[j]
		//                            , files[j].Substring(files[j].LastIndexOf(Path.DirectorySeparatorChar) + 1), shortName);
		//                }
		//            }
		//            //process features backup
		//            string featurePath = string.Format("configFiles{0}Features{0}{1}", Path.DirectorySeparatorChar, xmlFilename);
		//            string file = Cmn.pathCombine(root, featurePath);
		//            zipOutHelper(zOut, file, featurePath, shortName);
		//        }
		//    }

		//    //process StartupConfigs
		//    string confPath = Cmn.pathCombine(root, "configFiles");
		//    if (true.Equals(dInfo.get("includeStartUpConfig")) && Directory.Exists(confPath))
		//    {
		//        string path = "configFiles" + Path.DirectorySeparatorChar;
		//        string[] files = Directory.GetFiles(Cmn.pathCombine(root, path));
		//        for (int i = 0; i < files.Length; i++)
		//            zipOutHelper(zOut, files[i]
		//                , path + files[i].Substring(files[i].LastIndexOf(Path.DirectorySeparatorChar) + 1)
		//                , shortName);

		//    }
		//    //process imagecache backup
		//    string cachePath = string.Format("configFiles{0}Catalogs{0}ImageCache{0}", Path.DirectorySeparatorChar);
		//    string cacheName = Cmn.pathCombine(root, string.Format("{0}{1}images.xml", cachePath, shortName));
		//    zipOutHelper(zOut, cacheName
		//        , cachePath + cacheName.Substring(cacheName.LastIndexOf(Path.DirectorySeparatorChar) + 1)
		//        , shortName);

		//    //process basefeatures backup
		//    if (true.Equals(dInfo.get("includeBaseFeature")))
		//    {
		//        string basePath = string.Format("configFiles{0}BaseFeatures{0}", Path.DirectorySeparatorChar);
		//        processDirsAndFiles(zOut, root, basePath, new string[] { "*.xml" }, false, shortName);
		//    }

		//    //process app dependency dirs
		//    string basePagePath = "";
		//    if (true.Equals(dInfo.get("overrideRootPage")))
		//    {
		//        ///process base pages *.cs,*.config,*.dat, and 
		//        string[] filters = new string[] { "*.cs", "*.config", "*.dat", "*.asax" };
		//        processDirsAndFiles(zOut, root, "", filters, false, shortName);
		//        zipOutHelper(zOut, Cmn.pathCombine(root, "NitobiLiveStreamHandler.aspx"), "", shortName);
		//        zipOutHelper(zOut, Cmn.pathCombine(root, "AjaxRequestHandler.aspx"), "", shortName);
		//    }
		//    else
		//    {
		//        ///process base pages *.aspx, *.cs,*.config,*.dat and ajax support aspx
		//        string[] filters = new string[] { "*.aspx", "*.cs", "*.config", "*.dat", "*.asax" };
		//        processDirsAndFiles(zOut, root, "", filters, false, shortName);
		//        basePagePath = shortName + Path.DirectorySeparatorChar;
		//    }

		//    //process root dependency directories.
		//    string dirlist = dInfo.get("directories").ToString();
		//    if (dirlist.Length > 0)
		//    {
		//        if (dirlist.Contains(","))
		//        {
		//            string[] appDirs = dInfo.get("directories").ToString().Split(',');
		//            for (int i = 0; i < appDirs.Length; i++)
		//                processDirsAndFiles(zOut, Cmn.pathCombine(root, appDirs[i]), appDirs[i] + Path.DirectorySeparatorChar, null, true, shortName);
		//        }
		//        else
		//            processDirsAndFiles(zOut, Cmn.pathCombine(root, dirlist), dirlist + Path.DirectorySeparatorChar, null, true, shortName);
		//    }
		//    //process catalogs
		//    if (true.Equals(dInfo.get("includeCatalogs")))
		//    {
		//        if (dInfo.get("catalogs").ToString().Contains(","))
		//        {
		//            string[] dirs = dInfo.get("catalogs").ToString().Split(',');
		//            for (int i = 0; i < dirs.Length; i++)
		//            {
		//                string featurePath = string.Format("configFiles{0}Catalogs{0}{1}{0}", Path.DirectorySeparatorChar, dirs[i]);
		//                processDirsAndFiles(zOut, Cmn.pathCombine(root, featurePath), featurePath, null, true, shortName);
		//            }
		//        }
		//        else if ("full".Equals(dInfo.get("catalogs").ToString().ToLower()))
		//        {
		//            string featurePath = string.Format("configFiles{0}Catalogs{0}", Path.DirectorySeparatorChar);
		//            processDirsAndFiles(zOut, Cmn.pathCombine(root, featurePath), featurePath, null, true, shortName);
		//        }
		//    }

		//    if (true.Equals(dInfo.get("includeBin")))
		//    {
		//        string[] files = Directory.GetFiles(root.Substring(0, root.Length - 3));
		//        for (int i = 0; i < files.Length; i++)
		//        {
		//            string entryName = string.Format("bin{0}{1}", Path.DirectorySeparatorChar
		//            , files[i].Substring(files[i].LastIndexOf(Path.DirectorySeparatorChar) + 1));
		//            zipOutHelper(zOut, files[i], entryName, shortName);
		//        }
		//    }
		//}

		//public string createTemplateDataBackup(IApplication app, IRuleContext context,INameAddressSupport info)
		//{
		//    try
		//    {
		//        if (info.get("company") == null)
		//            throw new BackupRestoreDeployException("required company template is missing. error executing createTemplateDataBackup bizrule.");
		//        string root = app.resMgr.resolve("$ConfigParam1$");
		//        if (root.StartsWith("file://"))
		//            root = root.Substring(7);
		//        root = Cmn.pathCombine(root, string.Format("bktemp_{0}",info.get("company.shortName")));
		//        if (Directory.Exists(root))
		//        {
		//            string[] files = Directory.GetFiles(root);
		//            for (int i = 0; i < files.Length; i++)
		//                File.Delete(files[i]);
		//        }
		//        info.put("companyId", info.get("company.id") as Swaf.BGuid.Guid);
		//        info.put("objectTreeName", "Articles");
		//        info.put("includeSelf", true);
		//        info.put("listDetailLevel", DetailLevel.fullDetails);
		//        info.put("includeTranslations", true);
		//        info.put("defaultCacheName", info.get("company.settings.defaultMediaCache"));
		//        IResults rc = app.ruleMgr.execute("getArticles", info, (IBizObj)null);
		//        IBizObjList articles= null;
		//        if (rc.ExceptionInfo == null && rc.CallResults is IBizObjList)
		//        {
		//            articles= app.bizObjMgr.createList("Article");
		//            foreach (IBizObj book in (IBizObjList)rc.CallResults)
		//                articles.Add(book);
		//        }
		//        //process each book as xml
		//        if (articles != null)
		//        {
		//            foreach(IBizObj book in articles)
		//            {
		//                info.put("parentId", book.get("id"));
		//                info.put("entireTree", true);
		//                rc = app.ruleMgr.execute("getArticles", info, (IBizObj)null);
		//                if (rc.ExceptionInfo == null && rc.CallResults is IBizObjList)
		//                {
		//                    IBizObjList templist = app.bizObjMgr.createList("Article");
		//                    foreach (IBizObj child in (IBizObjList)rc.CallResults)
		//                        templist.Add(child);
		//                    Directory.CreateDirectory(root);
		//                    //TODO:write for now to file system.
		//                    //the info should pass in the zip file path for append
		//                    string fileName = string.Format("{0}{1}{2}_dat.xml", root, Path.DirectorySeparatorChar, book.get("id"));
		//                    File.WriteAllText(fileName,templist.Xml);
		//                }
		//            }
		//        }

		//        return root;
		//    }
		//    catch (Exception e)
		//    {
		//        throw new BackupRestoreDeployException("error executing createTemplateDataBackup.", e);
		//    }
		//}
		
		//public void addZipOutEntry(IApplication app, IRuleContext context, ZipOutputStream zOut, FileStream fileStream, string entryName)
		//{

		//}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="zOut"></param>
		/// <param name="dirPath"></param>
		/// <param name="filters">all files will be zipout on the dirpath if this value is null</param>
		protected void processDirsAndFiles(ZipOutputStream zOut, string rootDir, string curDir, string[] filters, string shortName, bool includeChildDirs, List<string> excludedDirs)
		{
			try
			{
				string actualDir = Cmn.pathCombine(rootDir, curDir);
				if (filters == null)
				{
					string[] files = Directory.GetFiles(actualDir);
					for (int i = 0; i < files.Length; i++)
					{
						FileAttributes fa = File.GetAttributes(files[i]);
						bool isHiddenOrSys = (((fa & FileAttributes.System) == FileAttributes.System) || ((fa & FileAttributes.Hidden) == FileAttributes.Hidden));

						if (!isHiddenOrSys && !files[i].EndsWith(".scc", StringComparison.OrdinalIgnoreCase))
						{
							string entry = Cmn.pathCombine(curDir, files[i].Substring(files[i].LastIndexOf(Path.DirectorySeparatorChar) + 1));
							zipOutHelper(zOut, files[i], entry, shortName);
						}
					}
				}
				else
					for (int j = 0; j < filters.Length; j++)
					{
						string[] files = Directory.GetFiles(actualDir, filters[j]);
						for (int i = 0; i < files.Length; i++)
						{
							string entry = Cmn.pathCombine(curDir, files[i].Substring(files[i].LastIndexOf(Path.DirectorySeparatorChar) + 1));
							zipOutHelper(zOut, files[i], entry,shortName);
						}
					}

				if (includeChildDirs)
					foreach (string childDir in Directory.GetDirectories(actualDir))
						{
							FileAttributes fa = File.GetAttributes(childDir);
							bool isHiddenOrSys = (((fa & FileAttributes.System) == FileAttributes.System) || ((fa & FileAttributes.Hidden) == FileAttributes.Hidden));
							if (!isHiddenOrSys)
							{
								DirectoryInfo childDirInfo = new DirectoryInfo(childDir);
								if (excludedDirs == null || !excludedDirs.Contains(childDirInfo.Name))
									processDirsAndFiles(zOut, rootDir, childDir.Substring(rootDir.Length), filters, shortName, includeChildDirs, null);
							}
						}
			}
			catch (Exception e)
			{
				throw new BackupRestoreDeployException("error executing processDirsAndFiles.", e);
			}
		}


		protected void zipOutHelper(ZipOutputStream zOut, string filePath,string entryName,string shortName) 
		{
			try
			{
				if (File.Exists(filePath))
				{
					string location = shortName==null?Cmn.pathCombine("bu", entryName):Cmn.pathCombine("bu",shortName,entryName);
					zOut.PutNextEntry(new ZipEntry(location));
					FileStream binDll = File.OpenRead(filePath);
					int b;
					while ((b = binDll.ReadByte()) != -1)
						zOut.WriteByte((byte)b);
					binDll.Close();
					binDll.Dispose();
				}
			}
			catch (Exception e)
			{
				throw new BackupRestoreDeployException("error executing zipOutHelper.", e);
			}
		}
		
	}
	
}
